--
-- Author: shineflag
-- Date: 2016-12-19 11:00:59
--

local skynet = require "skynet"
local gateserver = require "snax.gateserver"
local netpack = require "skynet.netpack"
local socketdriver = require "skynet.socketdriver"
local log = require "log"
local proto = require("json_proto")
local assert = assert

local TAG = "HALL"

local shake_ok    --握手成功后的工作
local server = {}

skynet.register_protocol {
	name = "client",
	id = skynet.PTYPE_CLIENT,
}

local user_online = {}  --已经在登录服务器上登录的用户
local handshake = {}    --刚建立连接 尚未验证(握手成功)的连接
local connection = {}   --已经验证过的连接


local function shake(fd, addr, msg, sz)
	local data = netpack.tostring(msg,sz)
	--log.d(TAG,"shake data[%s]",data)
	local token = proto.unpack_body(data)

	local ret = 200 
	local ret_msg = "ok"
	if token.cmd == "hall.shake" then 

		local req = token.req 
		local mid = req.mid 
		local secret = req.secret 

		local u = user_online[mid] 

		----[[ 改用go实现 http login
		if not u then 
			server.login(mid, req.secret)
			u = user_online[mid] 
		end
		--]]

		if not u or mid == 0 then 
			ret = -101
			ret_msg = "-101 user not found"
		elseif u.secret ~= secret then 
			ret = -102 
			ret_msg = "-102 user unauthorized"
		else
			if u.fd then 
				ret_msg =  string.format("you count login on addr[%s]",addr)
				local pkg = proto.create_resp("hall.kick",{ret=200, msg = ret_msg})
				socketdriver.send(u.fd, pkg)
				gateserver.closeclient(u.fd)
				connection[u.fd] = nil 
			end


			u.fd = fd 
			u.addr = addr 
			connection[fd] = u 
			shake_ok(mid, secret)
		end




	else
		ret = -103 
		ret_msg = "-103 error shake cmd:" .. token.cmd
	end


	local pkg = proto.create_resp("hall.shake",{ret=ret, msg = ret_msg, utime=os.time()})
	socketdriver.send(fd, pkg)
	if ret == 200 then 

	else 
		gateserver.closeclient(fd)
	end

end 

local function request(fd, msg, sz)
	local msg = netpack.tostring(msg,sz)
	log.e(TAG,"unknow msg:%s", msg)
end

--http 登录验证成功
function server.login(mid, secret)

	if user_online[mid] then
		log.d(TAG,"user[%d] repeat login on http",mid)
	else
		user_online[mid] = {
			secret = secret,
			mid = mid 
		}
	end
end

-- call by other server
function server.logout(mid)
	local u = user_online[mid]
	user_online[mid] = nil
	if u.fd then 
		gateserver.closeclient(u.fd)
		connection[u.fd] = nil 
	end
end


function server.send(mid, data)

	local u = user_online[mid]
	if not u then 
		log.e(TAG,"user[%d] offline",mid)
		return false 
	end
	if u.fd then
		--log.d(TAG,"fd[%d] send pkg[%s] ",u.fd, #data)
		socketdriver.send(u.fd, data)
		return true 
	else
		log.e(TAG,"user[%d] not fd",mid)
		return false 
	end
end


--主动关闭socket(一般在心跳包检测失败下会调用)
function server.socket_close(mid)
	local u = user_online[mid]
	if u and u.fd then 
		gateserver.closeclient(u.fd)
	else
		log.e(TAG,"user[%d] repeat socket_close", mid)
	end
end

function server.start( conf )
	local request_handler = assert(conf.request_handler)
	shake_ok = assert(conf.shake_ok)

	local handler = {}
	local CMD = {
		login = server.login,
		logout = assert(conf.logout_handler),
		kick = assert(conf.kick_handler),
	}

	function handler.command(cmd, source, ... )
		local f = CMD[cmd]
		if f then
			return f(...)
		else
			f = conf.command[cmd] 
			if f then
				return f(...)
			else
				log.e(TAG,"not cmd: [%s]",cmd)
			end
		end
	end

	function handler.open(source, gateconf)
		local sname = assert(gateconf.sname)
		return conf.register_handler(sname)
	end

	function handler.connect(fd, addr)
		handshake[fd] = addr 
		gateserver.openclient(fd)
		log.d(TAG,"connect fd[%d] addr[%s]",fd, addr)
	end


	function handler.disconnect(fd)
		log.d(TAG,"disconnect fd[%d]",fd)
		handshake[fd] = nil 
		local c = connection[fd]
		if c then 
			c.fd = nil 
			connection[fd] = nil 
			if conf.disconnect_handler then 
				conf.disconnect_handler(c.mid)
			end
		end
	end

	handler.error = handler.disconnect

	function handler.message(fd, msg, sz)
		local addr = handshake[fd]
		if addr then
			shake(fd,addr,msg,sz)
			handshake[fd] = nil
		else
			local c = connection[fd] 
			if c then 
				--local ok ,pkg = pcall(request_handler,c.mid, msg, sz )

				local message = netpack.tostring(msg, sz)
				local ok ,pkg = pcall(request_handler,c.mid, message )
				if ok then 
					-- if #pkg ~= 22 then --heart beat
					-- 	log.d(TAG,"fd[%d] send pkg[%s] ",fd, #pkg)
					-- end
					socketdriver.send(fd, pkg)
				else
					log.e(TAG,"user[%d] call info error[%s]",c.mid,pkg)
					gateserver.closeclient(fd)
				end
			else
				request(fd, msg, sz)
			end

		end
	end

	return gateserver.start(handler)
end

return server